package com.demo.spring.发布订阅底层演示;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ApplicationEventMulticaster;
import org.springframework.context.event.GenericApplicationListener;
import org.springframework.core.ResolvableType;
import org.springframework.stereotype.Component;

@Configuration
public class Test {
	
	public static void main(String[] args) {
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Test.class);
		context.getBean(MyService.class).doBusiness();
		context.close();
	}
	
	static class MyEvent extends ApplicationEvent {

		public MyEvent(Object source) {
			super(source);
		}
		
	}
	
	@Component
	static class MyService {
		@Autowired
		private ApplicationEventPublisher publisher; // ApplicationEventPublisher底层靠ApplicationEventMulticaster发送
		public void doBusiness() {
			System.out.println("主线业务");
			publisher.publishEvent(new MyEvent("MyService.doBusiness()"));
		}
	}
	
	@Component
	static class SmsApplicationListener implements ApplicationListener<MyEvent> {

		@Override
		public void onApplicationEvent(MyEvent event) {
			System.out.println("发送短信");
		}
		
	}
	
	@Component
	static class EmailApplicationListener implements ApplicationListener<MyEvent> {

		@Override
		public void onApplicationEvent(MyEvent event) {
			System.out.println("发送邮件");
		}
		
	}
	
	@Bean
	public ApplicationEventMulticaster applicationEventMulticaster(ConfigurableApplicationContext context) {
		return new AbstractApplicationEventMulticaster() {
			private List<GenericApplicationListener> listeners = new ArrayList<>();
			// 收集监听器
			@Override
			public void addApplicationListenerBean(String name) {
				ApplicationListener listener = context.getBean(name, ApplicationListener.class);
				System.out.println(listener);
				// 获取该监听器支持的事件类型
				ResolvableType type = ResolvableType.forClass(listener.getClass()).getInterfaces()[0].getGeneric(0);
				System.out.println(type);
				// 把原始的listener封装为支持事件类型检查的listener
				GenericApplicationListener genericApplicationListener = new GenericApplicationListener() {

					@Override
					public void onApplicationEvent(ApplicationEvent event) {
						listener.onApplicationEvent(event);
					}

					@Override
					public int getOrder() {
						return 0;
					}

					@Override
					public boolean supportsEventType(ResolvableType eventType) {
						return type.isAssignableFrom(eventType);
					}

					@Override
					public boolean supportsSourceType(Class<?> sourceType) {
						return false;
					}
					
				};
				listeners.add(genericApplicationListener);
			}
			
			// 发布事件
			@Override
			public void multicastEvent(ApplicationEvent event, ResolvableType eventType) {
				for(GenericApplicationListener listener : listeners) {
					if(listener.supportsEventType(ResolvableType.forClass(event.getClass()))) {
						listener.onApplicationEvent(event);
					}
				}
			}
		};
	}
	
	static class AbstractApplicationEventMulticaster implements ApplicationEventMulticaster {
		@Override
		public void addApplicationListener(ApplicationListener<?> listener) {
			// TODO Auto-generated method stub
			
		}
		@Override
		public void addApplicationListenerBean(String listenerBeanName) {
			// TODO Auto-generated method stub
			
		}
		@Override
		public void removeApplicationListener(ApplicationListener<?> listener) {
			// TODO Auto-generated method stub
			
		}
		@Override
		public void removeApplicationListenerBean(String listenerBeanName) {
			// TODO Auto-generated method stub
			
		}
		@Override
		public void removeAllListeners() {
			// TODO Auto-generated method stub
			
		}
		@Override
		public void multicastEvent(ApplicationEvent event) {
			// TODO Auto-generated method stub
			
		}
		@Override
		public void multicastEvent(ApplicationEvent event, ResolvableType eventType) {
			// TODO Auto-generated method stub
			
		}
	}
	
}
